﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
using PTA;
namespace PTA.App
{
    /// <summary>
    /// 系统操作类
    /// </summary>
    public static class Sys
    {
        /// <summary>
        ///系统时间类
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        private class SystemTime
        {
            internal ushort year;
            internal ushort month;
            internal ushort dayofweek;
            internal ushort day;
            internal ushort hour;
            internal ushort minute;
            internal ushort second;
            internal ushort milliseconds;
        }

        [DllImport("Kernel32.dll")]
        private static extern Boolean SetSystemTime([In, Out] SystemTime st);

        /// <summary>
        /// 设置系统时间
        /// </summary>
        /// <param name="dt">要设置的新时间</param>
        public static void SetSysTime(DateTime dt)
        {
            SystemTime st = new SystemTime();
            st.year = Convert.ToUInt16(dt.Year);
            st.month = Convert.ToUInt16(dt.Month);
            st.day = Convert.ToUInt16(dt.Day);
            st.dayofweek = Convert.ToUInt16(dt.DayOfWeek);
            st.hour = Convert.ToUInt16(dt.Hour - TimeZone.CurrentTimeZone.GetUtcOffset(new DateTime(2001, 09, 01)).Hours);
            st.minute = Convert.ToUInt16(dt.Minute);
            st.second = Convert.ToUInt16(dt.Second);
            st.milliseconds = Convert.ToUInt16(dt.Millisecond);
            SetSystemTime(st);
        }

        /// <summary>
        /// 获取程序集的版本号
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public static Version GetVersion(string path)
        {
            if (!System.IO.File.Exists(path))
            {
                throw new Exception("未找到文件");
            }
            return System.Reflection.Assembly.Load(path).GetName().Version;
        }

        #region 获取和当前程序集相同的进程实例
        /// <summary>
        /// 通过使用互斥条件和程序集的GuidAttribute来检查是否有一个实例在运行,如果有,返回运行的实例,否则返回null.
        /// <para>
        /// 这个方法要求为程序集的GuidAttribute属性设置一个唯一标识.
        /// </para>
        /// </summary>
        /// <example>
        /// Process running = GetProcessByGuid(out m);
        /// if (running != null)
        /// {
        ///     System.Windows.Forms.MessageBox.Show("已经有一个实例运行");
        ///     SetFocus(running);
        /// }
        /// </example>
        /// <param name="m">
        /// 互斥变量,这个变量要设置为一个在应用程序运行期间内存在的变量最好为全局静态变量,当应用程序退出时释放这个互斥变量
        /// </param>
        /// <returns>进程实例</returns>
        public static Process GetProcessByGuid(out Mutex m)
        {
            bool create = true;
            Assembly ca = Assembly.LoadFile(Process.GetCurrentProcess().MainModule.FileName);
            Console.WriteLine(Process.GetCurrentProcess().MainModule.GetType().FullName.ToString());
            GuidAttribute configuration = (GuidAttribute)AssemblyConfigurationAttribute.GetCustomAttribute(ca, typeof(GuidAttribute));
            if (configuration == null || string.IsNullOrEmpty(configuration.Value))
            {
                throw new Exception("未找到当前程序集的GuidAttribute信息");
            }
            string guid = configuration.Value.ToLower();
            m = new Mutex(false, guid, out create);
            if (!create)
            {
                //如果不能创建,表明已经存在一个实例,获取实例并置顶
                List<int> pids = new List<int>();
                Process current = Process.GetCurrentProcess();
                pids.Add(current.Id);

                Process[] olds = Process.GetProcessesByName(current.ProcessName);
                foreach (Process p in olds)
                {
                    if (pids.Contains(p.Id))
                    {
                        continue;
                    }
                    pids.Add(p.Id);

                    if (!CheckClrProcess(p))
                    {
                        continue;
                    }
                    try
                    {
                        Assembly a = Assembly.LoadFile(p.MainModule.FileName);
                        if (guid == ((GuidAttribute)AssemblyConfigurationAttribute.GetCustomAttribute(a, typeof(GuidAttribute))).Value.ToLower())
                        {
                            return p;
                        }
                    }
                    catch
                    {
                    }
                }

                Process[] all = Process.GetProcesses();
                foreach (Process p in all)
                {
                    if (pids.Contains(p.Id))
                    {
                        continue;
                    }
                    pids.Add(p.Id);
                    if (!CheckClrProcess(p))
                    {
                        continue;
                    }
                    try
                    {
                        Assembly a = Assembly.LoadFile(p.MainModule.FileName);
                        if (guid == ((GuidAttribute)AssemblyConfigurationAttribute.GetCustomAttribute(a, typeof(GuidAttribute))).Value.ToLower())
                        {
                            return p;
                        }
                    }
                    catch
                    {
                    }
                }
                pids.Clear();
            }

            return null;

        }

        /// <summary>
        /// 获取指定进程的GuidAttirbute
        /// </summary>
        /// <param name="p">进程信息</param>
        /// <returns>进程的GuidAttribute,如果没有找到返回null</returns>
        public static GuidAttribute GetProcessGuid(Process p)
        {
            Assembly ca = Assembly.LoadFile(p.MainModule.FileName);
            Console.WriteLine(Process.GetCurrentProcess().MainModule.GetType().FullName.ToString());
            GuidAttribute configuration = (GuidAttribute)AssemblyConfigurationAttribute.GetCustomAttribute(ca, typeof(GuidAttribute));
            return configuration;

        }
        #endregion

        #region 检查一个进程是否托管进程
        /// <summary>
        /// 检查一个进程是否托管进程
        /// </summary>
        /// <param name="p">进程</param>
        /// <returns>返回一个值,如果是托管进程,返回true,否则返回false</returns>
        public static bool CheckClrProcess(Process p)
        {
            try
            {
                return p.Modules.Exists<ProcessModule>(x => x.ModuleName.Equals("mscoree.dll", StringComparison.OrdinalIgnoreCase));
            }
            catch
            {
                return false;
            }
        }
        #endregion

        #region 把一个进程设置为焦点
        /// <summary>
        /// 把一个进程设置为焦点(置顶)
        /// </summary>
        /// <param name="instance"></param>
        public static void SetFocus(Process instance)
        {
            ShowWindowAsync(instance.MainWindowHandle, WS_SHOWNORMAL);
            SetForegroundWindow(instance.MainWindowHandle);
        }
        [DllImport("User32.dll")]
        private static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow);
        [DllImport("User32.dll")]
        private static extern bool SetForegroundWindow(IntPtr hWnd);
        private const int WS_SHOWNORMAL = 1;
        #endregion

        /// <summary>
        /// 执行一个命令
        /// </summary>
        /// <param name="cmd">命令</param>
        /// <param name="args">参数</param>
        /// <param name="milliseconds">等待时间</param>
        /// <returns>返回执行结果</returns>
        public static void ExecCommand(SystemCommand cmd, int milliseconds = 60000)
        {
            Thread t = new Thread(new ThreadStart(cmd.Execute));
            t.Start();
        }
    }

    /// <summary>
    /// Window命令行参数
    /// </summary>
    public class SystemCommand
    {
        public string FileName;
        public string Arguments;
        public int MilliSeconds;
        public string WorkingDirectory;
        public bool Success = true;
        private string result;
        public string Result
        {
            get { return this.result; }
        }
        internal void Execute()
        {
            using (Process p = new Process())
            {
                if (!string.IsNullOrWhiteSpace(WorkingDirectory))
                {
                    p.StartInfo.WorkingDirectory = WorkingDirectory;
                }
                p.StartInfo.Arguments = Arguments;
                p.StartInfo.FileName = FileName;
                p.StartInfo.RedirectStandardOutput = true;
                p.StartInfo.UseShellExecute = false;
                p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
                p.StartInfo.CreateNoWindow = true;
                p.Start();
                result = p.StandardOutput.ReadToEnd();
                p.WaitForExit(MilliSeconds);
                p.Close();
            }
            if (Callback != null)
            {
                Callback(result);
            }
        }
        public SystemCommandCallback Callback { get; set; }
    }
    public delegate void SystemCommandCallback(string text);
}
